#include "fixed.hpp"

#include <cmath>
#include <fstream>

namespace vl
{

/*
int fixed::cos_table[4096];
int fixed::sin_table[4096];
int fixed::angle_table[4097];
*/

// Makes an index in [0, 4096) for the ratio a / b
// Assumes a <= b && b > 0 && a / b >= 0 
inline int fixed_atan(fixed a, fixed b)
{
	return fixed::angle_table[static_cast<int>((static_cast<long long>(a.v) << (12)) / b.v)];
}

angle angle_of(basic_vec<fixed> v)
{
	if(v.x > vl::fixed(0))
	{
		if(v.y > vl::fixed(0))
		{
			if(v.x >= v.y)
				return angle(2097152*8 - fixed_atan(v.y, v.x));
			else
				return angle(2097152*6 + fixed_atan(v.x, v.y));
		}
		else
		{
			if(v.x >= -v.y)
				return angle(2097152*0 + fixed_atan(-v.y, v.x));
			else
				return angle(2097152*2 - fixed_atan(v.x, -v.y));
		}
	}
	else
	{
		if(v.y > vl::fixed(0))
		{
			if(-v.x >= v.y)
				return angle(2097152*4 + fixed_atan(v.y, -v.x));
			else
				return angle(2097152*6 - fixed_atan(-v.x, v.y));
		}
		else
		{
			if(v.x <= v.y)
			{
				if(!v.x)
					return angle(0); // Both v.x and v.y are 0
					
				return angle(2097152*4 - fixed_atan(v.y, v.x));
			}
			else
				return angle(2097152*2 + fixed_atan(v.x, v.y));
		}
	}
	
	return angle(0);
}

void fixed::generate_tables()
{
	for(int i = 0; i < 4096; ++i)
	{
		double a = -(i * pi * 2.0 / 4096.0);
		cos_table[i] = int(std::cos(a) * 65536.0);
		sin_table[i] = int(std::sin(a) * 65536.0);
	}
	
	for(int i = 0; i <= 4096; ++i)
		angle_table[i] = int(std::atan(i / 4096.0) * (2097152.0 / (pi / 4.0)));
}

void print_initializer(std::ostream& dest, int* b, int* e)
{
	bool first = true;
	
	int c = 0;
	
	dest << "{";
	for(; b != e; ++b, ++c)
	{
		if(!first)
			dest << ", ";
		else
			first = false;
		dest << *b;
		
		if((c % 20) == 0)
			dest << '\n';
	}
	
	dest << "}";
}

void fixed::print_tables()
{
	std::ofstream t("tables.txt");
	
	t << "int fixed::cos_table[4096] = ";
	print_initializer(t, cos_table, cos_table + 4096);
	t << ";\n\n";
	
	t << "int fixed::sin_table[4096] = ";
	print_initializer(t, sin_table, sin_table + 4096);
	t << ";\n\n";
	
	t << "int fixed::angle_table[4096] = ";
	print_initializer(t, angle_table, angle_table + 4097);
	t << ";\n\n";
}

}
